package lion.lan;

import java.util.concurrent.Executor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.AttributeKey;
import lion.common.NamedThreadFactory;
import lion.netty4.codec.ValueOnlyDecoder;
import lion.netty4.codec.ValueOnlyEncoder;
import lion.netty4.filter.MsgValidManger;
import lion.netty4.message.GamePlayer;

public class Netty4LanServer {

	public static final AttributeKey<Long> KEY_SESSION_ID = AttributeKey
			.valueOf(Netty4LanServer.class.getName() + ".SESSION_ID");

	public static final AttributeKey<MsgValidManger> KEY_MSG_VISIT_TIME = AttributeKey
			.valueOf(Netty4LanServer.class.getName() + ".MSG_VISIT_TIME");

	public static final AttributeKey<GamePlayer> KEY_GAME_PLAYER = AttributeKey
			.valueOf(Netty4LanServer.class.getName() + ".KEY_GAME_PLAYER");

	private static Logger logger = LoggerFactory.getLogger(Netty4LanServer.class);

	private int port;

	private EventLoopGroup bossGroup;

	private EventLoopGroup workerGroup;

	private Channel serverChannel;

	public Netty4LanServer(int port) {
		this.port = port;
	}

	public void run(ILanIoExecutor lanIoExecutor) throws Exception {
		run(Runtime.getRuntime().availableProcessors(), lanIoExecutor);
	}

	public void run(int threadCount, final ILanIoExecutor lanIoExecutor) throws Exception {
		run(threadCount, lanIoExecutor, null);
	}

	public void run(int threadCount, final ILanIoExecutor lanIoExecutor, Executor threadExecutor) throws Exception {
		int bossThreadCount = 0x1;
		if (threadExecutor == null) {
			bossGroup = new NioEventLoopGroup(bossThreadCount, new NamedThreadFactory("@+netty_boss_lan")); // (1)
			// io线程会去处理逻辑，因此数量要多一些，默认是2*coreCount
			workerGroup = new NioEventLoopGroup(threadCount, new NamedThreadFactory("@+netty_LAN_SERVER"));
		} else {
			bossGroup = new NioEventLoopGroup(0x1, threadExecutor); // (1)
			// io线程会去处理逻辑，因此数量要多一些，默认是2*coreCount
			workerGroup = new NioEventLoopGroup(threadCount, threadExecutor);
		}
		ServerBootstrap b = new ServerBootstrap();
		b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128)
				.childOption(ChannelOption.SO_KEEPALIVE, true).childOption(ChannelOption.SO_REUSEADDR, true)// 重用地址
				.option(ChannelOption.TCP_NODELAY, true).childHandler(new ChannelInitializer<SocketChannel>() {
					@Override
					public void initChannel(SocketChannel ch) throws Exception {
						ch.pipeline().addLast(new ValueOnlyDecoder(), new ValueOnlyEncoder(),
								new Netty4LanHandler(lanIoExecutor));
					}
				});
		// Bind and start to accept incoming connections.
		serverChannel = b.bind(port).sync().channel();
		logger.warn("Netty4 Lan Server listen on port:{},boss={},worker={} successfully!", port, bossThreadCount,
				threadCount);
	}

	public static void main(String[] args) throws Exception {
		int port;
		if (args.length > 0) {
			port = Integer.parseInt(args[0]);
		} else {
			port = 8653;
		}
		new Netty4LanServer(port).run(null);
	}

	public void shutdown() {
		try {
			// Wait until the server socket is closed.
			// In this example, this does not happen, but you can do that to gracefully
			// shut down your server.
			serverChannel.close().sync();
		} catch (InterruptedException e) {
			logger.error("", e);
		}
		workerGroup.shutdownGracefully();
		bossGroup.shutdownGracefully();
	}

}
